package day17.springdemo2;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Xiao
 * @date 2021/8/12
 */
public class ClasspathxmlApplicationContext implements ApplicationContext {

    /**定义一个Map集合，用于存储类名和该类的对象*/
    private Map<String, Object> map = new HashMap<>();

    /**定义ClasspathxmlApplicationContext类的有参构造接收传递过来的文件夹名称*/
    public ClasspathxmlApplicationContext(String dirPath) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        //获取文件中所有java文件的全类名
        List<String> javaNames = getDirJavaName(dirPath);
        //通过反射，将通过全类名创建的对象（值），以及全类名对应的类名（键）存入map集合中，且该类必须用@Anno注解
        map = createInstance(javaNames);
    }

    /**获取文件中所有java文件的全类名*/
    private List<String> getDirJavaName(String dirPath) {
        //创建一个list集合用于存储java文件的全类名
        List<String> list = new ArrayList<>();
        //通过指定的文件夹路径创建File对象
        File dirFile = new File(dirPath);
        //获取File的所有子文件
        File[] files = dirFile.listFiles();
        if (files != null) {
            for (File file : files) {
                //获取文件的相对路径：classpractice/src/day17/springdemo2/Person.java
                String filePath = file.getPath();
                //去掉相对路径中包名前面的部分：day17/springdemo2/Person.java
                int index = filePath.indexOf("src");
                String substring = filePath.substring(index + 4);
                //去掉文件后缀：day17/springdemo2/Person
                String s = substring.split(".java")[0];
                //将/用.代替，得到全类名：day17.springdemo2.Person
                String dirJavaName = s.replace("\\", ".");
//                System.out.println(dirJavaName);  //将结果打印，验证得到的全类名是否正确
                //将全类名添加到list集合中
                list.add(dirJavaName);
            }
        }
        return list;
    }


    /**创建对象：通过反射，将通过全类名创建的对象（值），以及全类名对应的类名（键）存入map集合中
     * 且该类必须用@Anno注解*/
    private Map<String, Object> createInstance(List<String> classNames) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //创建一个Map集合存储类名和对象
        Map<String, Object> map = new HashMap<>();
        for (String className : classNames) {
            //通过全类名获取字节码文件对象
            Class clazz = Class.forName(className);
            //判断该类是否使用@Anno注解,如果使用了@Anno注解，创建该类对象并存储至map集合
            if (clazz.isAnnotationPresent(Anno.class)) {
                //获取构造方法
                Constructor constructor = clazz.getConstructor();
                //创建对象
                Object instance = constructor.newInstance();
                //类名作为键，对象作为值，
                //getSimpleName()：获取类名
                String simpleName = clazz.getSimpleName();
                map.put(simpleName, instance);
            }
        }
        return map;
    }

    @Override
    /**传入一个类名，返回Object类对象*/
    public Object getBean(String name) {
        return map.get(name);
    }

    @Override
    /**传入一个类名，和T类的字节码对象，返回T类对象*/
    public <T> T getBean(String name, Class<T> type) {
        return (T) map.get(name);
    }
}
